package main

import (
	"bunker/pkg"
	"bunker/pkg/myfs"
	"fmt"
	"log"
	"os"

	"github.com/hanwen/go-fuse/v2/fs"
	"github.com/zh-five/xflag"
	"golang.org/x/term"
)

type App struct {
}

func (sf *App) Run() {

	flag := xflag.Flag()

	flag.Desc("用法: "+flag.Name()+" [cmd...] [option...] [param...]", "\n作者: xxx")

	// 绑定子命令
	flag.BindCmd("mount", sf.cmdMount, "启动服务")
	flag.BindCmd("save", sf.cmdSave, "保存文件")
	flag.BindCmd("help", nil, "查看帮助信息")

	help := flag.Bool("h", false, "查看帮助信息")
	flag.Parse()

	if *help || flag.CmdName == "" || flag.CmdName == "help" {
		flag.Usage()
	}
}

// cmdSave 保存文件
func (sf *App) cmdSave(flag *xflag.XFlagSet) {
	flag.Desc("用法: "+flag.Name()+" [-f] <file_name> <file_content>\n", "")
	isForce := flag.Bool("f", false, "若文件已经存在是否覆盖，默认不覆盖")
	flag.Parse()

	fileName := flag.Arg(0)    //文件名
	fileContent := flag.Arg(1) //文件内容

	if fileName == "" || fileContent == "" {
		flag.Usage()
		os.Exit(1)
	}

	fmt.Printf("%s -f %v %s %s", flag.Name(), isForce, fileName, fileContent)
	client := pkg.NewClient(pkg.SocketPath, sf.readPassword())
	err := client.SavaFile(fileName, []byte(fileContent), *isForce)
	fmt.Println(err)
}

// cmdMount 挂载目录
func (sf *App) cmdMount(flag *xflag.XFlagSet) {
	flag.Desc("启动bunker服务\n用法: "+flag.Name()+" <dir>", "")
	// key := flag.String("k", "", "指定密钥")
	flag.Parse()

	mount_dir := flag.Arg(0) // 挂载目录
	if mount_dir == "" {
		flag.Usage()
		os.Exit(1)
	}

	// 目录不存在则创建
	if _, err := os.Stat(mount_dir); os.IsNotExist(err) {
		os.MkdirAll(mount_dir, os.ModePerm)
	}

	opts := &fs.Options{}
	opts.Debug = false

	// 创建根目录
	root := myfs.NewDirInode(func(b []byte) fs.InodeEmbedder {
		return myfs.NewFileInode(b)
	})

	// 挂载 FUSE 文件系统
	server, err := fs.Mount(mount_dir, root, opts)
	if err != nil {
		log.Fatalf("Mount failed: %v\n", err)
	}
	defer server.Unmount()
	fmt.Println("Mounted")

	// 注册清理函数，在程序退出时卸载 FUSE 文件系统
	pkg.GS.RegisterCleanFunc(func() {
		server.Unmount()
		fmt.Println("\nfuse Unmount:", err)
	})

	// 启动服务
	pkg.StartServer(root, pkg.SocketPath, sf.readPassword())
}

func (sf *App) readPassword() []byte {
	var password []byte

	// 异步读取密码，避免阻塞主线程
	pwChan := make(chan struct{}, 1)
	go func() {
		defer func() {
			close(pwChan)
		}()

		// 从标准输入读取密码，且密码不可见
		fmt.Print("\npassword: ")
		var err error
		password, err = term.ReadPassword(int(os.Stdin.Fd()))
		fmt.Printf("password: %s, %v\n", string(password), err)
		if err != nil {
			log.Fatalf("Failed to read password: %v", err)
		}
	}()

	select {
	case <-pwChan:
		return password
	case <-pkg.GS.Ctx.Done():
		return nil
	}
}
